package com.gitee.wsl.jvm.reflect.autobox

import com.gitee.wsl.jvm.reflect.ReflectionUtils.cast

object Autoboxer {

    private val autoboxers: List<TypeAutoboxer<*>> = listOf(
        BooleanTypeAutoboxer(),
        InstantTypeAutoboxer(),
        IntegerTypeAutoboxer(),
        LongTypeAutoboxer(),
        DoubleTypeAutoboxer(),
        FloatTypeAutoboxer(),
        StringTypeAutoboxer(),
        UUIDTypeAutoboxer(),
        EnumAutoboxer(),
        DurationTypeAutoboxer()
    )

    fun <T> autobox(value: Any?, type: Class<T>): T? {
        if (value == null) return null

        if (type.isAssignableFrom(value.javaClass)) {
            return cast(value)
        }

        val book = autoboxers.stream()
            .filter { autoboxer -> autoboxer.supports(type) }
            .findFirst()
            .map<Any> { autoboxer  -> (autoboxer as TypeAutoboxer<T>).autobox(value, type ) }
            .orElseThrow<UnsupportedOperationException> {
                UnsupportedOperationException(
                    String.format(
                        "Cannot autobox %s of type %s to %s",
                        value,
                        value.javaClass.name,
                        type.name
                    )
                )
            }

        return cast(book)
    }
}
